package org.zxt.web.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class CusBodyBufferedInputStream extends BodyBufferedInputStream {
    private byte[] bodyBs;
    private SocketChannel socketChannel;
    private ByteBuffer bfTmp = ByteBuffer.allocate(4096*2);
    private int curLen = 0;
    private int curTotal = 0;
    boolean flag = true;
    public CusBodyBufferedInputStream(byte[] bodyBs, SocketChannel socketChannel){
        this.bodyBs = bodyBs;
        this.curTotal = bodyBs.length;
        this.socketChannel = socketChannel;
    }
    @Override
    public int readIn(ByteBuffer bf) throws IOException {
        if(flag) {
            if(bf.capacity() < bodyBs.length - this.curLen){
                byte[] bsTmp = new byte[bf.capacity()];
                System.arraycopy(bodyBs, this.curLen, bsTmp, 0, bf.capacity());
                this.curLen += bf.capacity();
                bf.put(bsTmp);
                return bf.capacity();
            } else {
                int len = bodyBs.length - this.curLen;
                byte[] bsTmp = new byte[len];
                System.arraycopy(bodyBs, this.curLen, bsTmp, 0, len);
                bf.put(bsTmp);
                bodyBs = null;
                flag = false;
                return len;
            }
        } else {
            return socketChannel.read(bf);
        }
    }
/*
    @Override
    public int read(byte[] bf, int off, int len) throws IOException {
        if(this.curTotal == -1){
            throw new IOException("can not read cause is read over!");
        }
        if(flag) {
            if(len < this.curTotal - this.curLen){
                System.arraycopy(bodyBs, this.curLen, bf, off, len);
                this.curLen += len;
                return len;
            } else {
                int xlen = this.curTotal - this.curLen;
                int readLen = Math.min(xlen, len);
                System.arraycopy(bodyBs, this.curLen, bf, off, readLen);
                bodyBs = null;
                flag = false;
                curLen = 0;
                bfTmp.clear();
                return readLen;
            }
        } else {
            this.curTotal = socketChannel.read(bfTmp);
            if(this.curTotal == -1){
                return this.curTotal;
            }
            bfTmp.flip();
            bodyBs = bfTmp.array();
            flag = true;
            curLen = 0;
            return 0;
        }
    }*/

    @Override
    public int read(byte[] bf, int off, int len) throws IOException {
        if(this.curTotal == -1){
            return -1;
        }
        if(flag) {
            if(len < this.curTotal - this.curLen){
                System.arraycopy(bodyBs, this.curLen, bf, off, len);
                this.curLen += len;
                return len;
            } else {
                int xlen = this.curTotal - this.curLen;
                int readLen = Math.min(xlen, len);
                System.arraycopy(bodyBs, this.curLen, bf, off, readLen);
                bodyBs = null;
                flag = false;
                curLen = 0;
                curTotal = 0;
                bfTmp.clear();
                return readLen;
            }
        } else {
            int totalRead = 0;
            while (len >= bfTmp.capacity()) {
                this.curTotal = socketChannel.read(bfTmp);
                if(this.curTotal == -1){
                    return totalRead;
                }
                bfTmp.flip();
                System.arraycopy(bfTmp.array(), 0, bf, off+totalRead, this.curTotal);
                totalRead += this.curTotal;
                len -= this.curTotal;
                bfTmp.clear();
            }
            if(totalRead > 0){
                return totalRead;
            } else {
                this.curTotal = socketChannel.read(bfTmp);
                if(this.curTotal <= 0){
                    return this.curTotal;
                }
                flag = true;
                bodyBs = bfTmp.array();
                System.arraycopy(bodyBs, 0, bf, off, len);
                this.curLen = len;
                return len;
            }
        }
    }
    @Override
    public int read(byte[] b) throws IOException {
        return read(b, 0, b.length);
    }

    @Override
    public int read() throws IOException {
        throw new IOException("not support");
    }
}
